package com.hmdp.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.CacheClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalTime;
import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
@Slf4j

public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private CacheClient cacheClient;

    public Result queryById1(Long id) {
//未解决缓存击穿问题，解决缓存穿透问题

//        String key = CACHE_SHOP_KEY + id;
////        1.TODO： 从Redis中查询缓存
//        String shopJson = stringRedisTemplate.opsForValue()
//                .get(key);
//        log.info("redis 餐厅缓存:"+shopJson);
////        2.TODO: 缓存是否存在
//
//        if(StrUtil.isNotBlank(shopJson)) {
//            log.info("获取缓存成功");
//            Shop shop= JSONUtil.toBean(shopJson,Shop.class);
//            return  Result.ok(shop);
//        }
//        if(shopJson!=null){
//
//            return Result.fail("店铺信息不存在");
//
//        }
////        3.TODO 存在返回
////        4.TODO 不存在，查数据库
//
//
//
//        Shop shopbyId = this.getById(id);
////        log.info(shopbyId.toString());
////        5.TODO 不存在返回错误
//        log.info("无缓存");
//        if(shopbyId==null){
////            解决
//            stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);
//            return  Result.fail("店铺不存在");
//        }
////        6.TODO 存在写入redis
//        String jsonStr = JSONUtil.toJsonStr(shopbyId);
//        stringRedisTemplate.opsForValue().set(key,jsonStr,CACHE_SHOP_TTL, TimeUnit.MINUTES);
////        7.TODO 返回
//        return Result.ok(shopbyId);
//        ---第二次注解分割线

//        Shop shop=queryWithMustex(id);
//        if(shop==null){
//            return Result.fail("查询店铺状态异常");
//        }
//        return  Result.ok(shop);

        Shop shop=cacheClient.queryWithPassThrough(CACHE_SHOP_TTL,TimeUnit.MINUTES,CACHE_SHOP_KEY,id, Shop.class,this::getById);
        return Result.ok(shop);

    }

    @Override
    @Transactional
    public Result update(Shop shop) {


        if(shop.getId()==null){
            return Result.fail("店铺id不存在");
        }

        updateById(shop);

        String key = CACHE_SHOP_KEY + shop.getId().toString();

        stringRedisTemplate.delete(key);

        return Result.ok();
    }
    public Shop queryWithMustex(Long id){

//        缓存穿透
        String key = CACHE_SHOP_KEY + id;
//        1.TODO： 从Redis中查询缓存
        String shopJson = stringRedisTemplate.opsForValue()
                .get(key);
        log.info("redis 餐厅缓存:"+shopJson);
//        2.TODO: 缓存是否存在


        if(StrUtil.isNotBlank(shopJson)) {
            log.info("获取缓存成功");
            Shop shop= JSONUtil.toBean(shopJson,Shop.class);
            return  shop;
        }
        if(shopJson!=null){

            return null;

        }            String lockKey="lock:shop:"+key;
        Shop shopbyId = null;
        try {
            boolean isLock=trylock(lockKey);

            if(!isLock){

                Thread.sleep(50);
                return queryWithMustex(id);
            }

//        3.TODO 存在返回
//        4.TODO 不存在，查数据库


            shopbyId = this.getById(id);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            unlock(lockKey);
        }
//        log.info(shopbyId.toString());
//        5.TODO 不存在返回错误
        log.info("无缓存");
        if(shopbyId==null){
//            解决
            stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL, TimeUnit.MINUTES);
            return  null;
        }
//        6.TODO 存在写入redis
        String jsonStr = JSONUtil.toJsonStr(shopbyId);
        stringRedisTemplate.opsForValue().set(key,jsonStr,CACHE_SHOP_TTL, TimeUnit.MINUTES);
//        7.TODO 返回
        return shopbyId;



    }
//    private  boolean Shop

//    TODO 无法使用
//    private Shop queryWithLogticExpire(Long id){
//        String key=CACHE_SHOP_KEY+id;
//
//        String shopJson=stringRedisTemplate.opsForValue().get(key);
//        if(StrUtil.isBlank(shopJson)){
//
//
//            return null;
//        }
//
//
//        return null;
//
//
//    }
    public Result queryById(Long id){


//        Shop shop=cacheClient.queryWithLogicalExpire(20l,TimeUnit.SECONDS,CACHE_SHOP_KEY,id,Shop.class,this::getById);
            Shop shop=cacheClient.queryWithPassThrough(20l,TimeUnit.SECONDS,CACHE_SHOP_KEY,id,Shop.class,this::getById);
        return Result.ok(shop);
    }
    private boolean trylock(String key){
        Boolean b = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
        return BooleanUtil.isTrue(b);
    }
    private boolean unlock(String key){
        Boolean delete = stringRedisTemplate.delete(key);
        return delete;
    }

}
